/*
 * HandleRefCountMap.cpp
 *
 *  Created on: 2023年2月21日
 *      Author: terry
 */

#include "HandleRefCountMap.h"

HandleRefCountMap::HandleRefCountMap()
{
}

HandleRefCountMap::~HandleRefCountMap()
{
}

bool HandleRefCountMap::emptyHandle(const std::string& k)
{
	return countHandle(k) == 0;
}

size_t HandleRefCountMap::countHandle(const std::string& k)
{
	size_t count = 0;
	HandleSetPredicate pred = [&] (HandleSet& handleSet)
	{
		count = handleSet.size();
		return true;
	};
	findDo(k, pred);
	return count;
}

bool HandleRefCountMap::existsHandle(const std::string& k, Handle handle, int& count)
{
	bool got = false;
	HandleSetPredicate pred = [&] (HandleSet& handleSet)
	{
		count = handleSet.size();
		got = true;
		return true;
	};
	findDo(k, pred);
	return got;
}

size_t HandleRefCountMap::addHandle(const std::string& k, Handle handle)
{
	size_t count = 0;
	std::lock_guard< std::mutex > lock(m_mutex);

	iterator it = m_map.find(k);
	if (it != m_map.end())
	{
		HandleSet& handleSet = it->second;
		handleSet.insert(handle);
		count = handleSet.size();
	}
	else
	{
		HandleSet handleSet;
		handleSet.insert(handle);
		count = 1;

		m_map[k] = handleSet;
	}
	return count;
}

size_t HandleRefCountMap::removeHandle(const std::string& k, Handle handle)
{
	size_t count = 0;
	std::lock_guard< std::mutex > lock(m_mutex);

	iterator it = m_map.find(k);
	if (it != m_map.end())
	{
		HandleSet& handleSet = it->second;
		handleSet.erase(handle);
		count = handleSet.size();

		if (count == 0)
		{
			m_map.erase(it);
		}
	}
	return count;
}

void HandleRefCountMap::clearHandle(const std::string& k)
{
	HandleSetPredicate pred = [&] (HandleSet& handleSet)
	{
		handleSet.clear();
		return true;
	};
	findDo(k, pred);
}

size_t HandleRefCountMap::clearHandle(Handle handle, KeyRefCountArray& countArray)
{
	size_t count = 0;
	std::lock_guard< std::mutex > lock(m_mutex);
	iterator it = m_map.begin();
	while (it != m_map.end())
	{
		HandleSet& handleSet = it->second;
		size_t eraseCount = handleSet.erase(handle);
		count = handleSet.size();
		if (eraseCount > 0)
		{
			KeyRefCount refCount(it->first, count);
			countArray.push_back(refCount);

			if (count == 0)
			{
				it = m_map.erase(it);
				break;
			}
		}

		++it;
	}

	return count;
}

HandleRefCountMap::HandleArray HandleRefCountMap::getHandles(const std::string& k)
{
	HandleArray handles;
	HandleSetPredicate pred = [&] (HandleSet& handleSet)
	{
		getHandles(handleSet, handles);
		return true;
	};
	findDo(k, pred);
	return handles;
}

bool HandleRefCountMap::empty()
{
	std::lock_guard< std::mutex > lock(m_mutex);
	return m_map.empty();
}

size_t HandleRefCountMap::size()
{
	std::lock_guard< std::mutex > lock(m_mutex);
	return m_map.size();
}

void HandleRefCountMap::clear()
{
	std::lock_guard< std::mutex > lock(m_mutex);
	m_map.clear();
}

size_t HandleRefCountMap::keys(StringArray& ids)
{
	std::lock_guard< std::mutex > lock(m_mutex);
	
	iterator it = m_map.begin();
	for (; it != m_map.end(); ++it)
	{
		ids.push_back(it->first);
	}
	return m_map.size();
}

size_t HandleRefCountMap::getHandles(HandleSet& handleSet, HandleArray& handles)
{
	size_t count = 0;
    for (Handle handle : handleSet)
    {
    	handles.push_back(handle);
		count++;
    }
    return count;
}

bool HandleRefCountMap::findDo(const std::string& k, HandleSetPredicate& pred)
{
	bool found = false;
	std::lock_guard< std::mutex > lock(m_mutex);

	HandleSetMap::iterator it = m_map.find(k);
	if (it != m_map.end())
	{
		pred(it->second);
		found = true;
	}
	return found;
}

size_t HandleRefCountMap::getCount(KeyRefCountArray& countArray)
{
	size_t count = 0;
	std::lock_guard< std::mutex > lock(m_mutex);

	iterator it = m_map.begin();
	for (; it != m_map.end(); ++it)
	{
		KeyRefCount refCount(it->first, it->second.size());
		countArray.push_back(refCount);
		count++;
	}
	return count;
}